var EXPORTED_SYMBOLS = [ "MLDonkeyDBConfig" ];

Components.utils.import("resource://mldonkeyff/MLDonkeyConstants.js");
Components.utils.import("resource://mldonkeyff/MLDonkeyUtils.js");
Components.utils.import("resource://mldonkeyff/MLDonkeyClient.js");

MLDonkeyDBConfig = new function() {
	var ioService = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
	var channel = ioService.newChannel("resource://mldonkeyffdb", null, null);
	var uri = channel.URI;
	var file = uri.QueryInterface(Components.interfaces.nsIFileURL).file;

	var storageService = Components.classes["@mozilla.org/storage/service;1"].getService(Components.interfaces.mozIStorageService);
	var dbConn = storageService.openDatabase(file);

	// Array of configured clients
	var clients = new Array(/* of MLDonkeyClient */);

	this.getConfiguredClients = function() {
		return clients;
	};

	/**
	 * Reloading of clients cause the disconnection of connected clients.
	 */
	this.reloadConfiguredClients = function() {
		// Disconnection of connected clients
		for (clientId in clients) {
			var client = clients[clientId];
			client.disconnect();
			delete client;
			delete clients[clientId];
		}
		//
		var statement = dbConn.createStatement("SELECT * FROM client_config");
		while (statement.executeStep()) {
			var id = null;
			var hostname = null;
			var port = null;
			var username = null;
			try {
				id = statement.row.id;
				hostname = statement.row.hostname;
				port = statement.row.port;
				username = statement.row.username;
				//
				var password = this.getCurrentClientLoginInfo(hostname, port, username).password;
				//
				clients[id] = new MLDonkeyClient(hostname, port, username, password)
			} catch (err) {
				dump("Clients on DB without login info (client data are id: " + id + ", hostname: " + hostname + ", port: " + port + ", username: " + username + ")\r\n");
			}
		}
	};

	this.getCurrentClientLoginInfo = function(hostname, port, username) {
		var clientId = MLDonkeyClient.createIdentifier(hostname, port, username);
		var logins = MLDonkeyUtils.getPasswordManager().findLogins({}, clientId, null, clientId);
		for (i in logins) {
			var login = logins[i];
			if (login.username == username) {
				return login;
			}
		}
		return null;
	};

	this.insertConfiguredClient = function(hostname, port, username, password) {
		try {
			var i = 0;
			// Begin transaction
			dbConn.beginTransactionAs(storageService.TRANSACTION_IMMEDIATE);
			//
			var statement = dbConn.createStatement("INSERT INTO client_config(\"hostname\", \"port\", \"username\") VALUES(:hostname, :port, :username)");
			statement.params["hostname"] = hostname;
			statement.params["port"] = port;
			statement.params["username"] = username;
			statement.execute();
			// Save the password
			var clientId = MLDonkeyClient.createIdentifier(hostname, port, username);
			var nsLoginInfo = new Components.Constructor("@mozilla.org/login-manager/loginInfo;1", Components.interfaces.nsILoginInfo, "init");
			var authLoginInfo = new nsLoginInfo(clientId, null, clientId, username, password, "", "");
			MLDonkeyUtils.getPasswordManager().addLogin(authLoginInfo);
			// Commit
			dbConn.commitTransaction();
		} catch (err) {
			// Rollback
			dbConn.rollbackTransaction();
			throw err;
		}
		//
		this.reloadConfiguredClients();
	};

	this.updateConfiguredClient = function(id, hostname, port, username, password) {
		try {
			var i = 0;
			// Begin transaction
			dbConn.beginTransactionAs(storageService.TRANSACTION_IMMEDIATE);
			//
			var statement = dbConn.createStatement("UPDATE client_config SET hostname = :hostname, port = :port, username = :username WHERE id = :id");
			statement.params.hostname = hostname;
			statement.params.port = port;
			statement.params.username = username;
			statement.params.id = id;
			statement.execute();
			// Update the password
			var currLoginInfo = this.getCurrentClientLoginInfo(hostname, port, username);
			var newLoginInfo = this.getCurrentClientLoginInfo(hostname, port, username);
			newLoginInfo.password = password;
			MLDonkeyUtils.getPasswordManager().modifyLogin(currLoginInfo, newLoginInfo);
			// Commit
			dbConn.commitTransaction();
		} catch (err) {
			// Rollback
			dbConn.rollbackTransaction();
			throw err;
		}
		//
		this.reloadConfiguredClients();
	};

	this.deleteConfiguredClient = function(id) {
		try {
			var i = 0;
			// Begin transaction
			dbConn.beginTransactionAs(storageService.TRANSACTION_IMMEDIATE);
			//
			var statement = dbConn.createStatement("DELETE FROM client_config WHERE id = :id");
			statement.params.id = id;
			statement.execute();
			//
			var client = clients[id];
			// Delete the password
			var currLoginInfo = this.getCurrentClientLoginInfo(client.getHostname(), client.getPort(), client.getUsername());
			MLDonkeyUtils.getPasswordManager().removeLogin(currLoginInfo);
			// Commit
			dbConn.commitTransaction();
		} catch (err) {
			// Rollback
			dbConn.rollbackTransaction();
			throw err;
		}
		//
		this.reloadConfiguredClients();
	};

	this.destroy = function() {
		dump("Destroying connections... \r\n");
		for (clientId in clients) {
			var client = clients[clientId];
			if (client.isConnected()) {
				dump("\tDisconnecting " + client.getIdentifier() + "\r\n");
				client.disconnect();
			}
		}
	};

	// Initialization
	dump("Prima di this.reloadConfiguredClients()\r\n");
	this.reloadConfiguredClients();
}
